package gu.sql2java.json;

import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.gitee.l0km.beanfilter.core.json.JacksonFilterableDeserializer;
import com.google.common.collect.FluentIterable;

import gu.sql2java.BaseBean;
import gu.sql2java.Constant;
import gu.sql2java.config.RuntimeConfig;
import static gu.sql2java.Sql2javaSupport.findSuperClass;

/**
 * implementation of BaseBean class for Jackson {@link JsonDeserializer},<br>
 * 
 * @author guyadong
 * @since 3.21.2
 */
public class JacksonDeserializer extends JacksonFilterableDeserializer implements Constant  {
	private static final long serialVersionUID = 7410414787512241455L;
	public JacksonDeserializer(Class<? extends BaseBean> beanClass) {
		super(beanClass, true, true);
	}
	@Override
	public BaseBean doDeserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
		// see also BeanDeserializer.vanillaDeserialize
		BaseBean bean = (BaseBean) _valueInstantiator.createUsingDefault(ctxt);
		Boolean _new = null;
		Integer initialized = null,modified = null;
		
		/** 输入中存在的字段 */
		LinkedHashSet<String> deserialized = new LinkedHashSet<>();
		/** 被过滤的字段 */
		HashSet<String> modifiedReset = new HashSet<>();
		/** 值过滤时被额外添加非null值的字段 */
		LinkedHashSet<String> modifiedSet = new LinkedHashSet<>();
        for(String propName = jp.nextFieldName();propName != null;propName = jp.nextFieldName()) {
        	jp.nextToken();
        	SettableBeanProperty prop = findProperty(this,propName);
        	if (prop != null) { // normal case
        		try {
        			switch(propName) {
        			case FIELD_NEW:
        				_new = (Boolean) prop.deserialize(jp,ctxt);
        				break;
        			case FIELD_INITIALIZED:
        				if(getSupplyFilter().permit(handledType(), prop.getName())) {
        					initialized = (Integer) prop.deserialize(jp,ctxt);
        				}
        				break;
        			case FIELD_MODIFIED:
        				if(getSupplyFilter().permit(handledType(), prop.getName())) {
        					modified = (Integer) prop.deserialize(jp,ctxt);
        				}
        				break;
        			default:
        				deserialized.add(prop.getName());
        				if(!deserializeProperty(jp, ctxt, bean, prop)) {
        					modifiedReset.add(propName);
        				}
        				break;
        			}
        		} catch (Exception e) {
        			wrapAndThrow(e, bean, propName, ctxt);
        		}
        		continue;
        	}
            handleUnknownVanilla(jp, ctxt, bean, propName);
        }
        if(null != _new) {
        	bean.setNew(_new);
        }
		if(null != initialized){
			bean.setInitialized(initialized);
		}
		if(null != modified){
			bean.setModified(modified);
		}
		processUndeserialized(bean,deserialized, modifiedSet);
		if(!modifiedReset.isEmpty()) {
			bean.resetModified(modifiedReset.toArray(new String[modifiedReset.size()]));
		}
		if(!modifiedSet.isEmpty()) {
			bean.modified(modifiedSet.toArray(new String[modifiedSet.size()]));
		}
		if (null != findSuperClass(RuntimeConfig.getLocalConfig().getResetModifiedIfEqual(),handledType())) {
			bean.resetModifiedIfEqual();
		}
		return bean;
	}
	@Override
	protected <T> T processUndeserialized(T bean, Set<String> deserialized, Set<String> additional) throws IOException {
		/** 忽略new,initialized,modified字段 */
		deserialized = FluentIterable.from(deserialized).append(FIELD_NEW,FIELD_INITIALIZED,FIELD_MODIFIED).toSet();
		return super.processUndeserialized(bean, deserialized, additional);
	}
}
